#include "configwidget.h"

// Qt Includes
#include <QtDebug>
#include <QDir>
#include <QDomDocument>
#include <QFileDialog>
#include <QList>
#include <QMessageBox>

// Local Includes
#include "filelister.h"
#include "plugin.h"
#include "pluginlistwidgetitem.h"

/////////////////////////////////////////////////////////////////////
// Construction & Destruction
/////////////////////////////////////////////////////////////////////
CConfigWidget::CConfigWidget(QWidget *pParent/* = NULL*/, Qt::WFlags windowFlags/* = 0*/)
	: QWidget(pParent, windowFlags)
{
	setupUi(this);

	// Signals & Slots.
	connect(m_pBrowseButton, SIGNAL(clicked()), this, SLOT(onBrowseSourcePath()));
	connect(m_pPluginListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
			this, SLOT(onPluginListWidgetItemChanged(QListWidgetItem*)));
	connect(m_pSendProjectButton, SIGNAL(clicked()), this, SLOT(onSendProject()));
}

CConfigWidget::~CConfigWidget()
{
	qDeleteAll(m_lstPlugins);
}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
// Member Functions
/////////////////////////////////////////////////////////////////////
void CConfigWidget::setConfigPayload(const QString &strXml)
{
	QDomDocument xmlDocument;

	if(!xmlDocument.setContent(strXml))
		return;

	// Clear out any existing plugins.
	qDeleteAll(m_lstPlugins);
	m_lstPlugins.clear();

	const QDomElement xmlDocumentElement = xmlDocument.documentElement();

	if(xmlDocumentElement.isNull())
		return;

	const QDomNodeList xmlNodeList = xmlDocumentElement.childNodes();
	const int nNodeListCount = xmlNodeList.count();

	if(nNodeListCount == 0)
		return;

	for(int i = 0; i < nNodeListCount; i++)
	{
		const QDomNode xmlNode = xmlNodeList.at(i);

		if(xmlNode.isNull())
			continue;

		const QString strNodeName = xmlNode.nodeName();

		if(strNodeName == tr("plugin"))
		{
			CPlugin *const pPlugin = new CPlugin;

			if(!pPlugin->loadFromXml(xmlNode.toElement()))
			{
				delete pPlugin;
				continue;
			}

			m_lstPlugins.append(pPlugin);
			continue;
		}
	}

	updatePluginListWidget();
}

void CConfigWidget::updatePluginListWidget()
{
	m_pPluginListWidget->clear();

	const int nPluginCount = m_lstPlugins.count();

	if(nPluginCount == 0)
	{
		onPluginListWidgetItemChanged(NULL); // Clear the Ui.
		return;
	}

	foreach(CPlugin *pPlugin, m_lstPlugins)
	{
		m_pPluginListWidget->addItem(new CPluginListWidgetItem(pPlugin));
	}

	m_pPluginListWidget->setCurrentRow(0);
}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
// Private Slots
/////////////////////////////////////////////////////////////////////
void CConfigWidget::onBrowseSourcePath()
{
	const QString strSourcePath = QFileDialog::getExistingDirectory(this, tr("Choose Source Path"),
			QDir::homePath(), QFileDialog::ShowDirsOnly);

	if(strSourcePath.isEmpty())
		return;

	m_pSourcePathLineEdit->setText(strSourcePath);
}

void CConfigWidget::onPluginListWidgetItemChanged(QListWidgetItem *pCurrent)
{
	CPluginListWidgetItem *pPluginListWidgetItem = static_cast<CPluginListWidgetItem*>(pCurrent);

	if(!pPluginListWidgetItem)
		return;

	updateCurrentPluginDetails(pPluginListWidgetItem->getPlugin());
}

void CConfigWidget::onSendProject()
{
	const QString &strSourcePath = m_pSourcePathLineEdit->text();

	if(strSourcePath.isEmpty())
	{
		QMessageBox::critical(this, tr("Invalid Source Path"),
				tr("You must choose a source path if you wish to send a project."));
		return;
	}

	const QDir theDir(strSourcePath);

	if(!theDir.isReadable())
	{
		QMessageBox::critical(this, tr("Invalid Source Path"),
				tr("The selected source path could not be read."));
		return;
	}

	// TODO: Use the thread-pool so we don't block.
	CFileLister theFileLister(strSourcePath, QStringList() << "*.h" << "*.cpp");

	theFileLister.run();

	emit sendProject(theFileLister.getDirsRelativeFilePaths(), getProjectConfigPayload());
}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
// Member Functions
/////////////////////////////////////////////////////////////////////
void CConfigWidget::updateCurrentPluginDetails(CPlugin *pPlugin)
{
	if(!pPlugin)
	{
		m_pPluginNameLabel->setText(QString());
		m_pTypeLabel->setText(QString());
		m_pDescriptionLabel->setText(QString());
		return;
	}

	m_pPluginNameLabel->setText(pPlugin->getPluginName());
	m_pTypeLabel->setText(CPlugin::pluginTypeToString(pPlugin->getPluginType()));
	m_pDescriptionLabel->setText(pPlugin->getDescription());
}

QString CConfigWidget::getProjectConfigPayload() const
{
	QDomDocument xmlDocument;
	QDomElement xmlElement = xmlDocument.createElement(QObject::tr("project"));

	const int nPluginCount = m_pPluginListWidget->count();

	for(int i = 0; i < nPluginCount; i++)
	{
		const CPluginListWidgetItem *const pPluginListWidgetItem =
				static_cast<CPluginListWidgetItem*>(m_pPluginListWidget->item(i));

		if(!pPluginListWidgetItem)
			continue;

		const CPlugin *const pPlugin = pPluginListWidgetItem->getPlugin();

		if(!pPlugin)
			continue;

		xmlElement.appendChild(pPlugin->saveToXml(xmlDocument));
	}

	xmlDocument.appendChild(xmlElement);

	return xmlDocument.toString();
}
/////////////////////////////////////////////////////////////////////
